#include "Cr.h"
#include "CrHashedString.h"
#include "CrCrc.h"

#if CR_MAINTAIN_HASH_STRING_LOOKUP
#include <string.h>
#include <map>
#include <vector>
#include <algorithm>
#endif // CR_MAINTAIN_HASH_STRING_LOOKUP

namespace cr
{
#if CR_MAINTAIN_HASH_STRING_LOOKUP

	struct HashLookup
	{
		typedef std::pair<uint32_t, const char*> Pair;
		static HashLookup* pInstance;
		std::vector<Pair>	m_lookup;

		HashLookup()
		{
		}

		static bool Sorter(const Pair& a, const Pair& b)
		{
			return a.first < b.first;
		}

		bool AlreadyContains(uint32_t val)
		{
			return Find(val) ? true : false;
		}

		const char* Find(uint32_t val)
		{
			for (std::vector<Pair>::iterator it = m_lookup.begin(), end = m_lookup.end(); it != end; ++it)
			{
				if (it->first == val)
					return it->second;
			}
			return 0;
		}
	};

	static HashLookup g_hashLookup;

#endif // CR_MAINTAIN_HASH_STRING_LOOKUP

	HashedString::HashedString()
		: m_hash( 0 )
	{

	}

	HashedString::HashedString( const HashedString& hsOther )
		: m_hash( hsOther.m_hash )
	{

	}

	HashedString::HashedString( const char* szString )
	{
		Set( szString );
	}

	HashedString::HashedString( const std::string& szString )
	{
		Set( szString.c_str() );
	}

	void HashedString::Set( const char* szString )
	{
		if (szString)
		{
			m_hash = crc32( (unsigned char*)szString, strlen( szString ) );

#if CR_MAINTAIN_HASH_STRING_LOOKUP
			HashLookup::Pair newPair(m_hash,szString);

			if (!g_hashLookup.AlreadyContains(m_hash))
			{
				g_hashLookup.m_lookup.push_back( newPair );
				std::sort( g_hashLookup.m_lookup.begin(), g_hashLookup.m_lookup.end(), HashLookup::Sorter );
			}
#endif
		}
		else
		{
			m_hash = 0;
		}
	}

	const char* HashedString::GetString() const
	{
		const char* szString = g_hashLookup.Find(m_hash);
		return szString ? szString : "?";
	}
}